home *** CD-ROM | disk | FTP | other *** search
/ PC World 2000 February / PCWorld_2000-02_cd.bin / Software / Servis / FFE / COMM.SWG / 0009_SQUISH Messages.pas < prev    next >
Pascal/Delphi Source File  |  1997-05-11  |  31KB  |  619 lines

  1. This Document is a subset of the complete document taken from the Squish
  2. Developers Kit Version 2.0
  3.  
  4.  
  5.                        COPYRIGHT AND DISTRIBUTION RESTRICTIONS
  6.  
  7. All of the source code, header files and documentation within the Squish
  8. Developers  Kit is copyright 1991-1994 by SCI Communications. All rights
  9. reserved.
  10.  
  11.                            SQUISH FILE FORMAT SPECIFICATION
  12.  
  13. This  section  describes  the physical file  layout  of a Squish message
  14. base.  This  is intended as a  reference  for developers who are writing
  15. their  own  Squish-compatible  programs. For  an  overview of the Squish
  16. message   base,   see   the  section   of   SQUISH.PRN  entitled  "Using
  17. Squish-Format Message Areas".
  18.  
  19. While  the  Squish MsgAPI library  provides  a standardized interface to
  20. Squish  and  *.MSG  bases  for  C  programmers,  authors  who  use other
  21. languages  may  need  to  access  Squish  bases  directly.  This section
  22. describes the implementation details of the Squish file format.
  23.  
  24.  
  25.           Squish Philosophy
  26.  
  27. A  standard Squish base consists of two files: a message data file and a
  28. message  index file. Both files have the  same prefix, but the data file
  29. has  an  extension of ".sqd", while the  index  file has an extension of
  30. ".sqi".
  31.  
  32. From an overall point of view, the Squish data file consists of messages
  33. stored  in a doubly-linked list. The  Squish data file includes a header
  34. that  contains  pointers  to the first and  last  frames in the area, in
  35. addition to other area-specific information.
  36.  
  37. In  the  data file, a "frame" is  used  to hold an individual message. A
  38. frame  consists of a frame header (which contains links to the prior and
  39. next  messages),  followed  by  the  optional  message  header,  control
  40. information and message body fields.
  41.  
  42. This  "linked list of frames" approach is  ideal for a BBS message base.
  43. Almost all message base access is sequential, starting from a particular
  44. offset,  and  reading  or writing until the  end  of the message base is
  45. reached.  Since  each frame header contains  the offset of the prior and
  46. next  messages,  no disk accesses are  required to find the preceding or
  47. following messages.
  48.  
  49. The  index  file  is a flat array  of  Squish Index (SQIDX) records. The
  50. index  file  is used primarily for  performing random access look-ups by
  51. message number.
  52.  
  53. Unlike other message base formats, the Squish base is only loosely based
  54. on  the concept of "message numbers".  While all messages have a message
  55. number, these numbers can change at any time. By definition, the message
  56. numbers  in a Squish base always range  from 1 to the highest message in
  57. the  area.  Consequently, there are no  "gaps"  in message numbers, so a
  58. Squish message area never needs to be renumbered.
  59.  
  60. While this makes it easy to scan through all of the messages in an area,
  61. this also makes it difficult to find one specific message. Consequently,
  62. the concept of a "unique message identifier" or (UMSGID) is introduced.
  63.  
  64. When  a  message  is  created, it  is  assigned  a  32-bit UMSGID. These
  65. identifiers  are  unique  and NEVER  CHANGE.  Unique message numbers are
  66. never  "renumbered",  so once a UMSGID of  a message is obtained, it can
  67. always  be used to find the current message number of the given message,
  68. no matter how many messages have been added or deleted in the interim.
  69.  
  70.  
  71.           Squish Data Types
  72.  
  73. The  following  integral  types  are  used  in  the  Squish  file format
  74. definitions:
  75.  
  76.           Type      Size      Description
  77.           char      1 byte    A one-byte unsigned character.
  78.  
  79.           word      2 bytes   A two-byte unsigned integer.
  80.  
  81.           sword     2 bytes   A two-byte signed integer.
  82.  
  83.           dword     4 bytes   A four-byte unsigned integer.
  84.  
  85.           FOFS      4 bytes   A  four-byte unsigned integer.   This type is
  86.                               used to  store offsets  of frames  within the
  87.                               Squish data file.
  88.  
  89.           UMSGID    4 bytes   A four-byte unsigned  integer.  This  type is
  90.                               used to store unique message  identifiers for
  91.                               Squish messages.
  92.  
  93. The  types  above are stored in  the  standard Intel "backwords" format,
  94. with  the  least  significant  byte being  stored  first,  and  the most
  95. significant byte being stored last.
  96.  
  97.           A two-byte integer containing 0x1234 would be stored as follows:
  98.  
  99.                Offset    Value
  100.                0         0x34
  101.                1         0x12
  102.  
  103.           A  four-byte integer  containing  0x12345678 would  be stored  as
  104.           follows:
  105.  
  106.                Offset    Value
  107.                0         0x78
  108.                1         0x56
  109.                2         0x34
  110.                3         0x12
  111.  
  112.           The  Squish  file format also uses  a  number of abstract data
  113. types:
  114.  
  115. The  SCOMBO type is used for  describing a message date/time stamp. This
  116. structure has the following format:
  117.  
  118.           Name      Type      Ofs  Description
  119.           date      word      0    DOS bitmapped date value.  This field is
  120.                                    used to store a message date.
  121.  
  122.                                    The first five bits represent the day of
  123.                                    the month.  (A value of 1 represents the
  124.                                    first of the month.)
  125.  
  126.                                    The next four bits indicate the month of
  127.                                    the year. (1=January; 12=December.)
  128.  
  129.                                    The  remaining  seven bits  indicate the
  130.                                    year (relative to 1980).
  131.  
  132.           time      word      2    DOS  bitmapped time  value.   This field
  133.                                    used to store a message time.
  134.  
  135.                                    The first five bits indicate the seconds
  136.                                    value,  divided by  two.   This  implies
  137.                                    that all  message  dates and  times  get
  138.                                    rounded  to a  multiple of  two seconds.
  139.                                    (0  seconds  = 0;  16  seconds  = 8;  58
  140.                                    seconds = 29.)
  141.  
  142.                                    The next six  bits represent the minutes
  143.                                    value.
  144.  
  145.                                    The  remaining  five bits  represent the
  146.                                    hour value, using a 24-hour clock.
  147.  
  148.                     Total:    4 bytes
  149.  
  150.           The  NETADDR  type  is  used  for  describing  a  FidoNet network
  151.           address.  This structure has the following format:
  152.  
  153.           Name      Type      Offset    Description
  154.           zone      word      0         FidoNet zone number.
  155.  
  156.           net       word      2         FidoNet net number.
  157.  
  158.           node      word      4         FidoNet node number.
  159.  
  160.           point     word      6         FidoNet  point  number.     If  the
  161.                                         system  is not a  point, this field
  162.                                         should be assigned a value of zero.
  163.                     Total:    8 bytes
  164.  
  165. In  addition,  to  describe  an array  of  a  given  type, the "type[n]"
  166. notation  is  used.  For example, "char[6]"  represents  an array of six
  167. contiguous  characters.  Likewise, "UMSGID[12]"  represents  an array of
  168. twelve UMSGID types.
  169.  
  170.  
  171.           Data File Format
  172.  
  173.           The Squish data file consists of two major sections:
  174.  
  175.           1)   A fixed-length area  header, stored at the  beginning of the
  176.                file.
  177.  
  178.           2)   A variable-length  heap that comprises the rest of the file.
  179.                This part of the file is used for storing message text.
  180.  
  181. The  area  header  stores  pointers to the  head  and  tail of two major
  182. "chains"  of messages; the message chain and the free chain. The message
  183. chain  is used to find all active messages in an area. The free chain is
  184. used  for storing the locations of deleted messages, such that space can
  185. be reused at a later point in time.
  186.  
  187. The  Squish  data file always contains  a  copy of the following _sqbase
  188. structure at file offset 0:
  189.  
  190.           Name                Type      Offset    Description
  191.           len                 word      0         Length  of   the  _sqbase
  192.                                                   structure.
  193.  
  194.           reserved            word      2         Reserved for future use.
  195.  
  196.           num_msg             dword     4         Number  of   messages  in
  197.                                                   this  Squish base.   This
  198.                                                   should always be equal to
  199.                                                   the value of the high_msg
  200.                                                   field.
  201.  
  202.           high_msg            dword     8         Highest message number in
  203.                                                   this  Squish base.   This
  204.                                                   should always be equal to
  205.                                                   the value  of the num_msg
  206.                                                   field.
  207.  
  208.           skip_msg            dword     12        When        automatically
  209.                                                   deleting  messages,  this
  210.                                                   field indicates  that the
  211.                                                   first  skip_msg  messages
  212.                                                   in the area should not be
  213.                                                   deleted.   (If max_msg=50
  214.                                                   and    skip_msg=2,   this
  215.                                                   means  that  the  writing
  216.                                                   program    should   start
  217.                                                   deleting  from  the third
  218.                                                   message    whenever   the
  219.                                                   total    message    count
  220.                                                   exceeds 50 messages.)
  221.  
  222.           high_water          dword     16        The high water marker for
  223.                                                   this  area,  stored as  a
  224.                                                   UMSGID.    This field  is
  225.                                                   used  in  EchoMail  areas
  226.                                                   only.   This contains the
  227.                                                   UMSGID  of   the  highest
  228.                                                   message that  was scanned
  229.                                                   by   EchoMail  processing
  230.                                                   software.
  231.  
  232.           uid                 dword     20        This  field  contains the
  233.                                                   UMSGID to  be assigned to
  234.                                                   the next  message created
  235.                                                   in this area.
  236.  
  237.           base                char[80]  24        Name  and   path  of  the
  238.                                                   Squish base, as an ASCIIZ
  239.                                                   string, not including the
  240.                                                   extension.  This field is
  241.                                                   optional  and  will   not
  242.                                                   necessarily be filled out
  243.                                                   by all applications.  (If
  244.                                                   this    field    is   not
  245.                                                   supported,  it should  be
  246.                                                   initialized to ASCII 0.)
  247.  
  248.           begin_frame         FOFS      104       Offset of the first frame
  249.                                                   in the message chain.
  250.  
  251.           last_frame          FOFS      108       Offset of  the last frame
  252.                                                   in the message chain.
  253.  
  254.           free_frame          FOFS      112       Offset of the first frame
  255.                                                   in the free chain.
  256.  
  257.           last_free_frame     FOFS      116       Offset   of   the    last
  258.                                                   message   in   the   free
  259.                                                   chain.
  260.  
  261.           end_frame           FOFS      120       Offset   of  end-of-file.
  262.                                                   Applications  will append
  263.                                                   messages  to  the  Squish
  264.                                                   file from this point.
  265.  
  266.           max_msg             dword     124       Maximum     number     of
  267.                                                   messages to store in this
  268.                                                   area.      When   writing
  269.                                                   messages,    applications
  270.                                                   should dynamically delete
  271.                                                   messages  to   make  sure
  272.                                                   that    no    more   than
  273.                                                   max_msgs  exist  in  this
  274.                                                   area.
  275.  
  276.           keep_days           word      128       Maximum age  (in days) of
  277.                                                   messages  in  this  area.
  278.                                                   This    field    is   not
  279.                                                   normally      used     by
  280.                                                   applications.    However,
  281.                                                   it is used by SQPACK when
  282.                                                   performing a message area
  283.                                                   pack.
  284.  
  285.           sz_sqhdr            word      130       Size    of   the    SQHDR
  286.                                                   structure.            For
  287.                                                   compatibility with future
  288.                                                   versions  of  the  Squish
  289.                                                   file format, applications
  290.                                                   should use  this value as
  291.                                                   the  size  of  the  SQHDR
  292.                                                   structure,   instead   of
  293.                                                   using     a     hardcoded
  294.                                                   "sizeof(SQHDR)" value.
  295.  
  296.           reserved            char[124] 132       Reserved for future use.
  297.  
  298.                               Total:    256 bytes
  299.  
  300. To  examine  the  messages in a  Squish  base,  the application needs to
  301. follow  the message chain. To do this, start with the begin_frame and/or
  302. end_frame fields. These fields contain the offsets of the first and last
  303. frames (respectively) in the message base.
  304.  
  305. A frame in the message chain consists of a Squish Frame Header structure
  306. (SQHDR),   followed   by  the  XMSG   message  header,  message  control
  307. information, and message body.
  308.  
  309. A  frame  in the free chain consists  of  a SQHDR structure only. A free
  310. frame does not necessarily contain a message.
  311.  
  312.           A SQHDR structure always has the following format:
  313.  
  314.           Name           Type      Ofs  Description
  315.           id             dword     0    The  frame   identifier  signature.
  316.                                         This field must always be  set to a
  317.                                         value of 0xAFAE4453.
  318.  
  319.           next_frame     FOFS      4    Frame offset of the next  frame, or
  320.                                         0 if this is the last frame.
  321.  
  322.           prev_frame     FOFS      8    Frame offset of the prior frame, or
  323.                                         0 if this is the first frame.
  324.  
  325.           frame_length   dword     12   Amount of space  ALLOCATED for  the
  326.                                         frame, not including the space used
  327.                                         by the SQHDR itself.
  328.  
  329.           msg_length     dword     16   Amount of space USED in this frame,
  330.                                         including  the  size  of  the  XMSG
  331.                                         header,  the  control  information,
  332.                                         and the message  text.  This  field
  333.                                         does  NOT include  the size  of the
  334.                                         SQHDR itself.
  335.  
  336.           clen           dword     20   Length  of the  control information
  337.                                         field in this frame.
  338.  
  339.           frame_type     word      24   This field  can contain one  of the
  340.                                         following frame type values:
  341.  
  342.                                              0    Normal frame.  This frame
  343.                                                   contains an  XMSG header,
  344.                                                   followed  by  the message
  345.                                                   control  information  and
  346.                                                   the message body.  Normal
  347.                                                   frames  should  only   be
  348.                                                   encountered          when
  349.                                                   processing   the   normal
  350.                                                   message chain.
  351.  
  352.                                              1    Free  frame.   This frame
  353.                                                   has been  deleted, but it
  354.                                                   can   be  reused.     The
  355.                                                   amount of available space
  356.                                                   in the frame is  given by
  357.                                                   the  frame_length  field.
  358.                                                   Free  frames should  only
  359.                                                   be    encountered    when
  360.                                                   processing    the    free
  361.                                                   chain.
  362.  
  363.                                              2    LZSS  frame.   This frame
  364.                                                   type   is  reserved   for
  365.                                                   future use.
  366.  
  367.                                              3    Frame update.   The frame
  368.                                                   is   being   updated   by
  369.                                                   another  task.   This  is
  370.                                                   only  a  transient  frame
  371.                                                   type;  it indicates  that
  372.                                                   the  frame should  not be
  373.                                                   manipulated   by  another
  374.                                                   task.
  375.  
  376.                                              All  other   frame  types  are
  377.                                              reserved for future use.
  378.  
  379.           reserved       word      26   Reserved for future use.
  380.  
  381.                          Total:    28 bytes
  382.  
  383.  
  384. For  a normal frame type, the XMSG header immediately follows the Squish
  385. frame header. The XMSG structure has the following format:
  386.  
  387.           Name           Type      Ofs  Description
  388.  
  389.           attr           dword     0    Message  attributes.    This  is  a
  390.                                         combination  of  any  of  the  MSG*
  391.                                         attributes.  (See below.)
  392.  
  393.           from           char[36]  4    Name  of  the  user who  originated
  394.                                         this message.
  395.  
  396.           to             char[36]  40   Name  of  the  user  to  whom  this
  397.                                         message is addressed.
  398.  
  399.           subject        char[72]  76   Message subject.
  400.  
  401.           orig           NETADDR   148  Originating network address of this
  402.                                         message.
  403.  
  404.           dest           NETADDR   156  Destination network address of this
  405.                                         message.  (Used  for netmail  areas
  406.                                         only.)
  407.  
  408.           date_written   SCOMBO    164  Date that the message was written.
  409.  
  410.           date_arrived   SCOMBO    168  Date that the message was placed in
  411.                                         this Squish area.
  412.  
  413.           utc_ofs        sword     172  The  message  writer's offset  from
  414.                                         UTC, in minutes.   Currently,  this
  415.                                         field is not used.
  416.  
  417.           replyto        UMSGID    174  If  this message  is a  reply, this
  418.                                         field  gives  the  UMSGID   of  the
  419.                                         original message.   Otherwise, this
  420.                                         field is given a value of 0.
  421.  
  422.           replies        UMSGID[9] 178  If any replies for this message are
  423.                                         present,   this  array   lists  the
  424.                                         UMSGIDs   of   up  to   nine  reply
  425.                                         messages.
  426.  
  427.           umsgid         UMSGID    214  The UMSGID  of this message.   THIS
  428.                                         FIELD  IS ONLY VALID  IF THE MSGUID
  429.                                         BIT  IS  SET IN  THE  "ATTR" FIELD.
  430.                                         Older Squish programs do not always
  431.                                         set this field, so its contents can
  432.                                         only be trusted  if the MSGUID  bit
  433.                                         is set.
  434.  
  435.           __ftsc_date    char[20]  218  FTS-0001  compatible date.   Squish
  436.                                         applications should not access this
  437.                                         field directly.  This field is used
  438.                                         exclusively by tossers and scanners
  439.                                         for  preserving the  original ASCII
  440.                                         message date.   Squish applications
  441.                                         should  use  the  binary  dates  in
  442.                                         date_written  and  date_arrived  to
  443.                                         retrieve the message date.
  444.                          Total:    238 bytes
  445.  
  446.           Any  of the  following bitmasks can  be used  in the  XMSG "attr"
  447.           field:
  448.  
  449.           Attribute      Value          Description
  450.           MSGPRIVATE     0x00000001     The message is private.
  451.  
  452.           MSGCRASH       0x00000002     The  message  is  given  a  "crash"
  453.                                         flavour  when  packed.   When  both
  454.                                         MSGCRASH   and  MSGHOLD   are  both
  455.                                         enabled,  the  message  is given  a
  456.                                         "direct" flavour.
  457.  
  458.           MSGREAD        0x00000004     The  message has  been read  by the
  459.                                         addressee.
  460.  
  461.           MSGSENT        0x00000008     The  message  has  been packed  and
  462.                                         prepared  for   transmission  to  a
  463.                                         remote system.
  464.  
  465.           MSGFILE        0x00000010     The  message  has a  file attached.
  466.                                         The filename is given in the "subj"
  467.                                         field.
  468.  
  469.           MSGFWD         0x00000020     The  message  is in-transit;  it is
  470.                                         not addressed to one of our primary
  471.                                         addresses.
  472.  
  473.           MSGORPHAN      0x00000040     The  message  is  orphaned.     The
  474.                                         message  destination address  could
  475.                                         not be found in the nodelist.
  476.  
  477.           MSGKILL        0x00000080     The message should be  deleted from
  478.                                         the  local message base  when it is
  479.                                         packed.
  480.  
  481.           MSGLOCAL       0x00000100     The  message   originated  on  this
  482.                                         system.   This flag must be present
  483.                                         on  all  locally-generated  netmail
  484.                                         for Squish to function properly.
  485.  
  486.           MSGHOLD        0x00000200     The  message  should  be   given  a
  487.                                         "hold" flavour when  packed.   When
  488.                                         combined  with  the MSGCRASH  flag,
  489.                                         the  message  is  given a  "direct"
  490.                                         flavour.
  491.  
  492.           MSGXX2         0x00000400     Reserved for future use.
  493.  
  494.           MSGFRQ         0x00000800     The message is a file request.  The
  495.                                         filename  is  given  in the  "subj"
  496.                                         field.
  497.  
  498.           MSGRRQ         0x00001000     A  receipt  is  requested.     (Not
  499.                                         supported by Squish.)
  500.  
  501.           MSGCPT         0x00002000     This  message is  a receipt  for an
  502.                                         earlier MSGRRQ request.
  503.  
  504.           MSGARQ         0x00004000     An audit trail  is requested.  (Not
  505.                                         supported by Squish.)
  506.  
  507.           MSGURQ         0x00008000     This message is an  update request.
  508.                                         The filename is given in the "subj"
  509.                                         field.
  510.  
  511.           MSGSCANNED     0x00010000     This  echomail   message  has  been
  512.                                         scanned out to other systems.
  513.  
  514.           MSGUID         0x00020000     The  "uid"  field contains  a valid
  515.                                         UMSGID for this message.
  516.  
  517.  
  518.           Index File Format
  519.  
  520. The  index  file  provides random access  capability  for a Squish base.
  521. Given  a message number, the index file  can be used to quickly find the
  522. frame offset for that message.
  523.  
  524. Similarly,  given a UMSGID, the index file  can also be used to find the
  525. message number and/or the frame offset for the message.
  526.  
  527. The  Squish  index file is an  array of Squish Index (SQIDX) structures.
  528. Each  SQIDX  structure  corresponds  to an  active  message.  For a base
  529. containing 'n' messages, there are at least 'n' SQIDX structures. (There
  530. may  also be extra SQIDX frames at the  end of the index file, but these
  531. will be initialized with invalid values, as described below.)
  532.  
  533. The SQIDX for the first message is stored at offset 0. The SQIDX for the
  534. second  message is stored at offset 12.  The SQIDX for the third message
  535. is stored at offset 24. (and so on)
  536.  
  537.           The Squish Index structure (SQIDX) has the following format:
  538.  
  539.           Name      Type      Ofs  Description
  540.  
  541.           ofs       FOFS      0    Offset of the frame for this message.  A
  542.                                    value  of  0  is  used  to  indicate  an
  543.                                    invalid message.
  544.  
  545.           umsgid    UMSGID    4    Unique message ID for  this message.   A
  546.                                    value of 0xffffffff  is used to indicate
  547.                                    an invalid message.
  548.  
  549.                                    The umsgid field  must always be greater
  550.                                    than  the umsgid field  of the preceding
  551.                                    SQIDX structure.   UMSGIDs are  assigned
  552.                                    serially, so  this will normally  be the
  553.                                    case.  (A binary search is  performed on
  554.                                    the  index file to translate UMSGIDs, so
  555.                                    the  umsgid field  of the  SQIDX headers
  556.                                    must  always  be  stored   in  ascending
  557.                                    order.)
  558.  
  559.           hash      dword     8    The low 31 bits  of this field contain a
  560.                                    hash the "To:"  field for this  message.
  561.                                    (See below for the  hash function.)  The
  562.                                    high bit is set to 1 if the MSGREAD flag
  563.                                    is  enabled  in  the corresponding  XMSG
  564.                                    header.
  565.  
  566.                     Total:    12 bytes
  567.  
  568.  
  569. The following hash function is used to calculate the "hash" field of the
  570. SQIDX structure. All variables are 32-bit unless otherwise noted:
  571.  
  572.                Set "hash" to a value of 0
  573.  
  574.                For each 8-bit character "ch" in the To: field, repeat:
  575.  
  576.                     -    Shift "hash" left by four bytes.
  577.                     -    Convert "ch" to lowercase
  578.                     -    Increment the hash by the ASCII value of "ch"
  579.  
  580.                     -    Set "g" to the value of "hash"
  581.                     -    Perform a  bitwise AND  on  "g", using  a mask  of
  582.                          0xf0000000.
  583.  
  584.                     -    If "g" is non-zero:
  585.  
  586.                          -    Perform a bitwise OR on "hash" with the value
  587.                               of "g".
  588.                          -    Shift "g" right by 24 bits.
  589.                          -    Perform a bitwise OR on "hash" with the value
  590.                               of "g".
  591.  
  592.                Perform   a  bitwise  AND  on  "hash"  with  a  value  of
  593.                 0x7fffffff.
  594.  
  595.           The following C function can be used to calculate such a hash:
  596.  
  597.                #include <ctype.h>
  598.  
  599.                unsigned long SquishHash(unsigned char *f)
  600.                {
  601.                     unsigned long hash=0;
  602.                     unsigned long g;
  603.                     char *p;
  604.  
  605.                     for (p=f; *p; p++)
  606.                     {
  607.                          hash=(hash << 4) + (unsigned long)tolower(*p);
  608.  
  609.                          if ((g=(hash & 0xf0000000L)) != 0L)
  610.                          {
  611.                               hash |= g >> 24;
  612.                               hash |= g;
  613.                          }
  614.                     }
  615.                     /* Strip off high bit */
  616.  
  617.                     return (hash & 0x7fffffffLu);
  618.                }
  619.